/*
 Notes:
 
 Rule Priority:
 - Each rule has a unique priority, the bigger is the number, the higher is the priority of the rule.
 - The RuleListActivity lists the rules from highest priority to lowest priority in order.
 - The least priority is always 10, and each higher priority item increases 10.
 - When a new rule added, it will be the new highest priority.
 - When a new rule inserted in between or deleted, the rules will be updated to make sure everyone 
   gets proper priority number starting from 10, and increased by 10 for each higher rule.
 - A rule can swap the priority with previous or next rule in order to rearrange the order of the
   rules. When swap priority, only the two involved rules will be updated.
 
 */

package com.aricwang.easyprofile.rule;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import com.aricwang.easyprofile.R;
import com.aricwang.easyprofile.contentprovider.RuleContentProvider;
import com.aricwang.easyprofile.database.RuleTable;
import com.aricwang.easyprofile.place.Place;
import com.aricwang.easyprofile.profile.Profile;
import com.aricwang.easyprofile.service.ProfileService;

/*
 * A ListActivity subclass to list all the rules.
 */
public class RuleListActivity extends ListActivity implements View.OnClickListener, ListView.OnItemLongClickListener {
	public static final int REQ_ADD  = 1;
	public static final int REQ_EDIT = 2;
	public static final int REQ_COPY = 3;
	
	public static final int DIALOG_WARNING = 1;
	public static final int DIALOG_ADD = 2;
	public static final int DIALOG_LONG_CLICK = 3;
	
	private CursorAdapter mAdapter;
	
	// used to pass information to dialog
	private int mId;
	
	/////////////////////////////////////////////////////////////////////////////////////////
	// Static functions
	/////////////////////////////////////////////////////////////////////////////////////////
	


	/////////////////////////////////////////////////////////////////////////////////////////
	// Override functions
	/////////////////////////////////////////////////////////////////////////////////////////

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// set the layout
		setContentView(R.layout.list);
		Button add = (Button)findViewById(R.id.btn_add);
		add.setText(getText(R.string.new_rule));

		// set the onItemLongClick handler of the ListView
		ListView listView = getListView();
		listView.setOnItemLongClickListener(this);

		// get the list of profile from content provider
		try {
			String sortOrder = RuleTable.COLUMN_PRIORITY + " desc";
			Cursor cursor = getContentResolver().query(RuleContentProvider.CONTENT_URI, 
					RuleTable.ALL_COLUMNS, null, null, sortOrder);
			startManagingCursor(cursor);
			
			// create the cursor adapter
			mAdapter = new CursorAdapter(this, R.layout.rule_list_row, cursor, RuleTable.ALL_COLUMNS, null);
			
			// finally, set the ListAdapter
			setListAdapter(mAdapter);
		} catch (Exception e) {
			Log.e("RuleListActivity", "Exception: " + e.toString());
		}
	}
	
	// onClick handler of interface View.OnClickListener
	public void onClick(View v) {
		CursorAdapter.ButtonTag tag;
		
		switch(v.getId()) {
		case R.id.btn_add:
			showDialog(DIALOG_ADD);
			break;
		case R.id.up:
			tag = (CursorAdapter.ButtonTag)v.getTag();
			increaseRulePriority(tag.position);
			setSelection(tag.position - 1);
			ProfileService.notifyConfigChanged(this);
			break;
		case R.id.down:
			tag = (CursorAdapter.ButtonTag)v.getTag();
			decreaseRulePriority(tag.position);
			setSelection(tag.position + 1);
			ProfileService.notifyConfigChanged(this);
			break;
		default:
			break;
		}
	}

	// onItemLongClick handler of interface ListView.OnItemLongClickListener
	public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
		RuleListActivity activity = (RuleListActivity)v.getContext();

		// id is the id database, save it to activity
		activity.mId = (int)id;

		activity.showDialog(RuleListActivity.DIALOG_LONG_CLICK);
		
		// database may changed, update the adapter
		mAdapter.notifyDataSetChanged();

		// Return true to consume the click event. In this case the
		// onListItemClick listener is not called anymore.
		return true;
	}
	
	protected Dialog onCreateDialog(int id) {
	    Dialog dialog = null;
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
	    switch(id) {
	    case DIALOG_WARNING:
            builder.setMessage(R.string.warning_rule_name_empty)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                    	dialog.dismiss();
                    }
                });
            dialog = builder.create();
	    	break;
	    	
	    case DIALOG_ADD:
	    	LayoutInflater factory = LayoutInflater.from(this);
            final View textEntryView = factory.inflate(R.layout.dialog_edit_text, null);
            
            builder.setTitle(R.string.new_rule)
                .setView(textEntryView)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                    	// use textEntryView to find the EditText????
                        EditText editText = (EditText)textEntryView.findViewById(R.id.edit_text);
                    	String name = editText.getText().toString();
                    	dialog.dismiss();
                    	
                    	// if name is empty, warn user
                    	if (name.length() <= 0) {
                    		RuleListActivity.this.showDialog(RuleListActivity.DIALOG_WARNING);
                    	} else {
	            			// start the ProfileActivity
                    		RuleActivity.startActivity(RuleListActivity.this, RuleListActivity.REQ_ADD, 0, name);
                    	}
                    }
                })
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked cancel so do some stuff */
                    	dialog.cancel();
                    }
                });
            dialog = builder.create();	
	        break;
	        
	    case DIALOG_LONG_CLICK:
	    	final String[] items = { getString(R.string.edit), getString(R.string.delete), getString(R.string.copy) };
	    	final RuleListActivity activity = (RuleListActivity)this;
	    	
	    	builder.setTitle(R.string.please_select)
	    		.setItems(items, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						String action = items[which];
						dialog.dismiss();

						if (action == getString(R.string.edit)) {
	            			// start the RuleActivity
                    		RuleActivity.startActivity(activity, RuleListActivity.REQ_EDIT, activity.mId, null);
						} else if (action == getString(R.string.copy)) {
	            			// start the RuleActivity
                    		RuleActivity.startActivity(activity, RuleListActivity.REQ_COPY, activity.mId, null);
						} else if (action == getString(R.string.delete)) {
							Rule.deleteRule(activity, activity.mId);
						}
					}
				});
	    	dialog = builder.create();
	    	break;
	    	
	    default:
	    	break;
	    }
	    
	    return dialog;
	}
	
	protected void onPrepareDialog(int id, Dialog dialog) {
	    switch(id) {
	    case DIALOG_ADD:
            EditText editText = (EditText)dialog.findViewById(R.id.edit_text);
//            editText.setText("");
	    	break;
	    default:
	    	break;
	    }
	}

	/////////////////////////////////////////////////////////////////////////////////////////
	// Private functions
	/////////////////////////////////////////////////////////////////////////////////////////
	
	
	/////////////////////////////////////////////////////////////////////////////////////////
	// Inner classes
	/////////////////////////////////////////////////////////////////////////////////////////

	/*
	 * A SimpleCursorAdapter subclass to generate the row view of the rule list.
	 */
	private class CursorAdapter extends SimpleCursorAdapter {
		public class ButtonTag {
			public int id;				// id field of database record
			public int position;		// position in the list view
			public int priority;		// priority field of record
		}
		
		private int mLayoutId;
		private RuleListActivity mActivity;
		private Cursor  mCursor;
		
		public CursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
			super(context, layout, c, from, to);
						
			mActivity = (RuleListActivity)context;
			mLayoutId = layout;
			mCursor = c;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			mCursor.moveToPosition(position);
			
			int id       = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_ID));
			String name  = mCursor.getString(mCursor.getColumnIndex(RuleTable.COLUMN_NAME));
			int priority = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_PRIORITY));
			int profile  = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_PROFILE));
			
			int tfStartHour  = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_TIMEFRAME_START_HOUR));
			int tfStartMinute= mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_TIMEFRAME_START_MINUTE));
			int tfEndHour    = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_TIMEFRAME_END_HOUR));
			int tfEndMinute  = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_TIMEFRAME_END_MINUTE));
			int tfRepeat     = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_TIMEFRAME_REPEAT));
			int charging     = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_CHARGING));
			int place        = mCursor.getInt(mCursor.getColumnIndex(RuleTable.COLUMN_PLACE));

			String summary = makeSummary(profile, tfStartHour, tfStartMinute, tfEndHour, tfEndMinute, tfRepeat, charging, place);
			
			View rowView;
			
			if (convertView == null) {
				LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				rowView = inflater.inflate(mLayoutId, parent, false);	
			} else {
				rowView = convertView;
			}
			
			TextView idView = (TextView) rowView.findViewById(R.id.id);
			TextView nameView = (TextView) rowView.findViewById(R.id.name);
			TextView summaryView = (TextView) rowView.findViewById(R.id.summary);
//			LinearLayout opsView = (LinearLayout) rowView.findViewById(R.id.ops);
			Button upBtn = (Button)rowView.findViewById(R.id.up);
			Button downBtn = (Button)rowView.findViewById(R.id.down);

			idView.setText(Integer.toString(id));
			nameView.setText(name);
			summaryView.setText(summary);

			ButtonTag tag = new ButtonTag();
			tag.id = id;
			tag.position = position;
			tag.priority = priority;
					
			upBtn.setTag(tag);
			downBtn.setTag(tag);
			
			// for first item in list, disable the UP button
			if (position == 0) {
				upBtn.setEnabled(false);
			} else {
				upBtn.setEnabled(true);
			}
			
			// for last item in list, disable the DOWN button
			if (position == (mCursor.getCount() - 1)) {
				downBtn.setEnabled(false);
			} else {
				downBtn.setEnabled(true);
			}
			
			return rowView;
		}
		
		// TODO: replace the strings with resource ids
		private String makeSummary(int profileId, int tfStartHour, int tfStartMinute, int tfEndHour, int tfEndMinute, 
				int tfRepeat, int charging, int placeId) 
		{
			String summary = "";
			
			if ((tfRepeat & Rule.WEEK) > 0) {
				summary += String.format("Tiemframe: %02d:%02d ~ %02d:%02d\n (", 
						tfStartHour, tfStartMinute, tfEndHour, tfEndMinute);
				if ((tfRepeat & Rule.MON) > 0)
					summary += "Mon ";
					
				if ((tfRepeat & Rule.TUE) > 0)
					summary += "Tue ";

				if ((tfRepeat & Rule.WED) > 0)
					summary += "Wen ";

				if ((tfRepeat & Rule.THU) > 0)
					summary += "Thu ";

				if ((tfRepeat & Rule.FRI) > 0)
					summary += "Fri ";

				if ((tfRepeat & Rule.SAT) > 0)
					summary += "Sat ";

				if ((tfRepeat & Rule.SUN) > 0)
					summary += "Sun ";
				
				summary += ")";
			}
			
			if (charging == Rule.CHARGING) {
				summary += "\nWhen charging";
			} else if (charging == Rule.NOT_CHARGING) {
				summary += "\nWhen not charging";
			}
			
			if (placeId != Rule.NO_PLACE) {
				summary += "\nAt Place: " + Place.getPlaceNameById(mActivity, placeId);
			}
		
			summary += "\nProfile to Apply: " + Profile.getProfileNameById(mActivity, profileId);
			
			return summary;
		}
	}	


	private void increaseRulePriority(int position) {
		Cursor c = mAdapter.getCursor();
		
		// if already the highest priority, do nothing
		if (position == 0)
			return;

		c.moveToPosition(position);
		int current_id = c.getInt(c.getColumnIndex(RuleTable.COLUMN_ID));
		int current_priority = c.getInt(c.getColumnIndex(RuleTable.COLUMN_PRIORITY));
		
		c.moveToPosition(position - 1);
		int target_id = c.getInt(c.getColumnIndex(RuleTable.COLUMN_ID));
		int target_priority = c.getInt(c.getColumnIndex(RuleTable.COLUMN_PRIORITY));
		
		// swap the priority of the two records
		setRulePriority(current_id, target_priority);
		setRulePriority(target_id, current_priority);
	}
	
	private void decreaseRulePriority(int position) {
		Cursor c = mAdapter.getCursor();
		
		// if already the lowest priority, do nothing
		if (position == (c.getCount() - 1))
			return;

		c.moveToPosition(position);
		int current_id = c.getInt(c.getColumnIndex(RuleTable.COLUMN_ID));
		int current_priority = c.getInt(c.getColumnIndex(RuleTable.COLUMN_PRIORITY));
		
		c.moveToPosition(position + 1);
		int target_id = c.getInt(c.getColumnIndex(RuleTable.COLUMN_ID));
		int target_priority = c.getInt(c.getColumnIndex(RuleTable.COLUMN_PRIORITY));
		
		// swap the priority of the two records
		setRulePriority(current_id, target_priority);
		setRulePriority(target_id, current_priority);
	}
	
	private void setRulePriority(int id, int priority) {
		Uri uri = Uri.parse(RuleContentProvider.CONTENT_URI + "/" + id);
		ContentValues values = new ContentValues();
		values.put(RuleTable.COLUMN_PRIORITY, priority);
		
		getContentResolver().update(uri, values, null, null);
	}
}

